home *** CD-ROM | disk | FTP | other *** search
-
- DOC file for TrapIIv1.11b © 1992 Nicolas Dade.
- Permission is hereby granted for non-commercial distribution and duplication.
- last changed: Feb 4th, 1992
-
- TrapII is of no use of you are not programming in a compiled language. It is
- of greatest use to an assembly language programmer.
-
- Some of the things TrapII does fall in the category of hacks, so no
- guarantee is stated or implied by the author concerning the suitability of
- this program for any purpose what so ever, and the author can take no
- responsibility as to any damages, disappointments, etc... that follow the
- (attempted) use of this program. However, on the bright side, this program
- has worked as described on the author's A1000 under WB1.3.
-
- TrapII tries to help you (the programmer) by giving you much more
- information when your program (hereafter also referred to as the target)
- causes the 680x0 to enter exception handling code than does the normal
- system default. That is, now when the target tries to read/write a word/long
- from/to an odd address, instead of getting a requestor "system
- requestor/software error/task held/finish all disk activity/cancel to
- debug/reset", followed by a GURU which tells you it was you program that had
- the odd address, you get a (SMART refresh) window from TrapII...
-
-
-
- New in 1.3: (1.1 & 1.2 were just bug fixes)
- 1) Safer task restarting: version 1.2 could make a mess of the target's
- signals if there were interrupts and other tasks talking to the target.
- Because of this new code not only is Forbid() used (correctly this time),
- but for about 20 clock cycles (68000), Disable() is too.
- 2) target_wait code changed to support Disable().
-
- New in 1.4:
- 1) Got rid of the screen moving thing, and changed the screen to front so
- that it calls ScreenToFront(wd's screen) instead WBenchToFront()
-
- New in 1.6: (1.5 was bug fix)
- 1) Changed window gadgets so that [Off] is gone (use rmb), [OK/Ignore] is
- gone (use close gadget), and a new one, [Trace], is given. With trace
- you can step through your code instruction by instruction, until you
- are tired of this, and just hit [Restart].
- 2) Safe handling of USP. Now your task can use a7 for anything it desires-
- it does not have to point to a stack. TrapII allocates a mini-stack
- for the target to use when the target is being shutdown and restarted.
- 3) Got rid of the ScreenToFront() when the TrapII window opens altogether.
-
- New in 1.7
- 1) Added [Next] gadget & function.
- 2) Window is no longer closed after [Restart], [Trace] or [Next] is pressed.
- This saves a lot of time on a clogged wb screen, and reminds you that
- the task is off doing something.
- 3) Changed the offset/segment finding code so that if the target is started
- from WB the offset/segment can still be found, and so that if the segment
- list seems too long (i.e. corrupted), we are not in a perpetual loop
-
- New in 1.8
- 1) Added keyboard equivalents for the gadgets:
- [Next] = N
- [Trace] = T
- [Restart] = R
- 2) Fixed bug in TrapII which was generating address errors (which I traced by
- having two TrapIIs running one on top of the other, and using the second
- to trace through the first!)
-
- New in 1.9
- 1) Added keyboard equivalents for close and sleep
- Close/Ok/Ignore = O
- Sleep = Z
- 2) Added support for [Next]ing through loops which end in BCC
- 3) Window deiconifies when a key is pressed (well, most keys)
-
- New in 1.10
- 1) Fixed window closing code in hope of avoiding crashes.
-
- New in 1.11
- 1) Found that bug!, and fixed it for good. (the one where if you click twice
- on anything really quickly then you get an addr error).
- 2) Changed wd closing code to use arp.library's CloseWindowSafely()
-
- New in 1.11b
- 1) Bug fix of bug in version distributed to ab20 (sorry).
-
-
-
- The contents of the window TrapII opens for each trap are best explained
- by looking at an example:
- To see this example in real life, open a CLI, cd to the directory TrapII
- is in, and type the following two lines:
- run <nil: >nil: TrapII
- run demo
- (the source for demo is as follows:
- TRAP #$0 ; cause a TRAP #$0 trap
- TRAP #$F ; cause a TRAP #$F trap
- MOVEQ.L #9,d0
- MOVEQ.L #0,d1
- label ; this loop is used to demo [Trace]
- ADDQ.L #1,d1
- DBF.W d0,label
- TRAP #$1 ; cause a TRAP #$1 trap after the loop
- BSR.S subroutine ; used to demo [Next]
- MOVE.W D0,label+1 ; cause an address error trap
- CLR.L D0 ; actually, this instruction is never reached
- RTS
-
- subroutine
- MOVE.W #$FFFF,D2
- MOVE.W #$004F,D3
- sub_loop
- DBF.W D2,sub_loop
- DBF.W D3,sub_loop
- RTS
- )
- (If you like, the demo can also be run from workbench. Double-click TrapII,
- then double-click demo.)
-
- You should see, in the workbench screen, a window looking like:
-
- ++
- line 1 |D nnnnnnnn A nnnnnnnn FUNC -,-,----|
- 2 |1 nnnnnnnn 1 nnnnnnnn ---- |
- 3 |2 nnnnnnnn 2 nnnnnnnn ADDR --------|
- 4 |3 nnnnnnnn 3 nnnnnnnn /--------,--|
- 5 |4 nnnnnnnn 4 nnnnnnnn INST ---- |
- 6 |5 nnnnnnnn 5 nnnnnnnn (SP) nnnnnnnn|
- 7 |6 nnnnnnnn 6 nnnnnnnn 4() nnnnnnnn|
- 8 |7 nnnnnnnn SP nnnnnnnn 8() nnnnnnnn|
- 9 | SR nnnnnnnnnnnnnnnn C() nnnnnnnn|
- 10 | T-S--III---XNZVC TRAP #$0 |
- 11 | PC nnnnnnnn/00000002,00 ++
- 12 |PROC demo |RemTask()|
- 13 | nnnnnnnn +++++
- 14 |hh:mm:ss |Restart| Next | Trace |
- +++++
-
- (n,h,m and s represent values that may be different each time demo is run)
- (n represents a hex number, hh,mm,ss represent decimal)
- the information is grouped in fields, as shown below:
-
- ++
- line 1 | | | |
- 2 | Data Regs | Addr Regs| Address Data|
- 3 | | | |
- 4 | | | AD |
- 5 | DR | AR |_____________|
- 6 | | | |
- 7 | | | Top of Stack|
- 8 |___________|__________| SK |
- 9 | |_____________|
- 10 | SR & PC |___Trap__TP__|
- 11 |________________________| |
- 12 | Task TK _____________| Gadgets |
- 13 |__________| GG |
- 14 | Time TM | (or status) |
- ++
-
- ** DR **
- The data registers as they were then the trap occurred. The contents are
- given as hexadecimal unsigned longs.
- (When I write trap, I mean when the 68000 entered exception processing
- code. When I write TRAP, I mean the TRAP #n instruction.)
-
- ** AR **
- The address registers as they were then the trap occurred. The contents are
- given as unsigned longs. SP (A7), is the user stack pointer (USP), regardless
- of what the 68000's mode was when the trap occured.
-
- ** SR **
- The status register (SR) the 680x0 pushed on the stack when the trap occur-
- red, in binary. Below (line 10) is the meaning of the bits of the SR for a
- 68000.
-
- ** PC **
- The PC the 680x0 pushed on the stack when the trap occurred, given two
- ways.
- The first is the absolute value of the PC. This points to the instruction
- following the instruction that caused the trap, except in the case of bus
- and address errors, in which case it may point to somewhere in the instruc-
- tion that caused the trap. The PC points to the next instruction in memory,
- not the next it would have executed. Thus if the offending instruction was
- a JMP (to an odd address), for example, the PC points to just beyond the
- JMP in memory, not the address to jump to. This representation of the PC
- is useful if you are using a disassembler/debugger to look in memory.
- If you are using a disassembler, get is started and look at the address
- PC. You should see the code for demo, with the PC pointing to the second
- TRAP instruction (the TRAP #$f).
- The second representation of the PC (after the "/") is the offset from the
- start of the hunk the PC points in, followed by the hex number of that
- hunk (0 = first hunk). So 00000002,00 indicates that the PC points to an
- address 2 bytes beyond the start of the first hunk. A look at the source
- for demo (above) will show the PC points to the instruction following the
- first TRAP #0. This value is usefull for looking at the listing the assembler
- created, and for some disassemblers and debuggers which look at the segment
- lists of loaded commands.
- (The hunk number must be less than 255, or no hunk number will be displayed)
-
- ** SK **
- These are the top four long words on the user stack. These are correct
- even if the USP is odd. Line 6 shows the topmost data. These are only useful
- in conjunction with a disassembler (if the trap occurred in a subroutine,
- you can see from where that routine was called).
-
- ** TP **
- This is a text description of the trap that occurred. Currently it says a
- TRAP #$0 instruction was reached. It can also say:
- Bus Error, Address Error, Illegal Instruction, Zero Divide, CHK Instruction,
- TRAPV Instruction, Privilege Violation, Trace, Line 1010 Emulation, Line
- 1111 Emulation, Next (used with [Next]), and, if the trap type is none of
- the above, trap nnnnnnnn, where nnnnnnnn is the number of the trap that
- occurred.
-
- ** TK **
- This field tries to identify what task/process caused the trap. First
- (line 12) are the letters "PROC" or "TASK", stating whether the target is
- a task or a process. In this case, demo was started by a CLI, and so is a
- process.
- To the right of this are up to 19 characters of text. These are the "best"
- name for the target TrapII could find:
- If the target is a task, then this is the name of the task, as pointed to
- by LN_NAME(target task structure).
- If the target is a process, then
- If the target has a CLI, then
- If the CLI has a non null command name (pointed to by cli_CommandName),
- then this is that command name.
- else this is the task name, just as if the target were a task.
- Below (line 13) gives the address of the target's task/process structure.
-
- ** TM **
- This is the system time at which the trap occurred. This is not very exact,
- but it will allow you to look at multiple TrapII windows, and determine
- which is the "freshest." The time is the ONLY numerical value that is not
- in hexadecimal in the TrapII windows.
-
- ** GG **
-
- [Restart] (or the R key)
- This sets the target running where it stopped with the trace bit cleared.
- This only works if a set of conditions are all met:
- [RemTask()] has not been used.
- The trap was due to a TRAP #n instruction or a Trace (or a Next, which is
- really a TRAP #$n).
- The target has some signal bits allocated that are not used by its exception
- code. (as of now, signal bits 0-15 are guarenteed to fall in this category,
- so don't worry about this)
- And the target has entered a wait state. (the target has proceeded out of
- my trap handler, to some shutdown code.)
- This function allows TrapII to be used to halt/look at your program at
- selected places by putting a TRAP instruction where you want to halt and
- look at your program, or restart your program to full speed execution after
- you have stopped it.
- Once the target has been restarted, the gadgets are replaced by the text
- "Target Restarted" until the target enters its exception code again (say,
- from a TRAP #$n which you placed in your code, or [Next]'s TRAP #$0 at the
- exit of the subroutine which you [Next]ed into).
-
- [Trace] (or the T key)
- This sets the target running where it stopped with the trace bit set. Same
- conditions as for [Restart] apply.
- Actually first looks at the next instruction. If it is a TRAP, TRAPV, and if
- the execution of the instruction would generate an exception, then the
- instruction is just executed, with the trace bit off.
- If the instruction is a CHK or a DIV, no tracing is tried, because the
- potential double trap due to CHK being out of bounds or a DIV by 0 and the
- Trace sends the TrapII trap handler into a guru! Therefore a "Next" is always
- used when you try to [Trace] these instructions (this is done automatically
- for you, you just press [Trace])
-
- [Next] (or the N key)
- This only works on a few instructions. It puts a TRAP #n just beyond the
- next instruction, then sets the target running where it stopped with the
- trace bit cleared. It only works on BCC, BSR, DBCC and JSR instructions,
- and uses the address of the instruction following the BCC, BSR, DBCC or
- JSR, and on the BRA.s, BRA and JMP instruction, where it uses the address
- on the stack (this is an easy speed up when a subroutine ends with the
- calling of another subroutine) (if you try to [Trace] a CHK or DIV, the
- [Next] function is used, but you cannot explicitly [Next] a CHK or DIV).
- The idea of this is to allow subroutines (or system calls) that you know
- work/don't want to trace through to execute a full speed, but still stop
- the target when it returns back to the subroutine level at which you were.
- Once the target stops because of the TRAP #n, the word I changed in order
- to put a TRAP #n is restored, and the task is stopped for a Next trap.
- [Next], of course, does not work if you are in ROM, since it must alter the
- next instruction.
- NOTE: If you close the window of a task which is [Nexting] then the code
- is restored; you have essentially done a [Restart].
- WARNING: you may NOT nest [Next] calls. Do not do a [Next] into a subroutine
- which contains a TRAP, and then [Next] inside that subroutine to a second
- one, or the first [Next] will be canceled (its Trap #n removed).
- WARNING: if the subroutines called are such that the target never gets back
- to the instruction following the BCC, BSR, DBCC or JSR, or the address on
- the stack at a BRA or JMP then by doing a [Next] you have essentially done a
- [Restart], since the target will never get back to the TRAP #n which would
- stop it. You will not confuse TrapII by doing this, but remember that the
- instruction (or first word thereof) which was changed to a TRAP #n is not
- restored until THAT TRAP #n is reached. While a [Next] is being done, the
- window is not closed, but the gadgets are replaced by "-Doing [Next]-" to
- tell you that the target is executing.
- NOTE: since [Next] changes your code, if several tasks are running on the
- same code, all of them will react to the change; the target will find a
- Next exception, the others will find a TRAP #$0.
- NOTE: since [Next] reacts differently for a BRA and a BCC, you cannot [Next]
- through a subroutine which you get to by a BCC. (Maybe in the next version
- I will split the Next function into two: Next to next instruction and Next
- to addr on stack)
-
- [RemTask()]
- This does a RemTask(target). It is provided in order to unclutter your
- system task list of "old" invocations of your program OR to stop any excep-
- tion code from executing. If the target uses exception code, then you have
- better use this if you don't want your exception code to execute; TrapII
- does nothing to halt exception processing.
- After this function is used, [Restart] and [Trace] can no longer be used.
- This function does not close the TrapII window.
- This function does not free any memory used by the target.
-
- In addition:
-
- The Close Window Gadget (or the O key)
- This closes the TrapII window, and leaves the target as it is. If the
- target is not executing ([Restart], [Trace] or [Next]), and [RemTask()] has
- not been used, then the target is in a wait state, waiting for nothing
- (Wait(0)).
- If, during a [Restart], [Trace] or [Next] you close the window, then if some
- of you code has been changed in order to do a [Next], that code is restored
- in the process of closing the window. This means that if you close the
- window during a [Next] then you could just as well have done a [Restart],
- since the instruction which would have stopped the target at the exit of
- the subroutine is now gone.
-
- The Right Mouse Button (or the Z key)
- This shrinks the window to a small bar. To reopen the window, make the bar
- window active, then click the right mouse button.
-
-
- Back to the demo:
- Since our trap is a TRAP #0 instruction, we can use [Restart] to continue.
- Press it now. The task "demo" is restarted, executes the next instruction,
- TRAP #$F, enters exception handling code, which culminates in TrapII
- updating its window for the target with this new information.
- This is another TRAP #n instruction trap, so nothing much is new (except
- the PC has incremented by 2).
- Now lets try to trace through the loop. Press [Trace]. The task "demo"
- is restarted, but because the trace bit is set, one instruction executes
- and then the CPU internally generates trace exception, which causes it
- to enter exception handling code, and eventually TrapII undates the
- window to inform you of this. Keep pressing [Trace] and see the PC run
- through the loop, d0 count down and d1 count up.
- When you are tired of this, press [Restart]. Now the task "demo" is
- restarted with the trace bit cleared, so now it runs full speed until it
- finds the TRAP #$1 at the end of the loop. Since the next instruction
- is a BSR.S, we can use [Next] to let the subroutine execute at full speed
- but yet gain control of the target back once the subroutine is finished.
- Press [Next], and the subroutine counts down, returns, and then causes
- a Next trap. [Next] is a way to "trace" through subroutines that you are
- not interrested in actually [Trace]ing through (like system calls or
- subroutines that you know (ha!) have no bugs).
- Press [Restart] to send the target doing again until it causes an address
- error as it tries to load from the odd address label+1.
- Now the AD field is filled in.
-
- ** AD **
- This shows the information the 68000 dumps in its stack frame when a bus or
- address error occurs. It should look like:
-
- +
- line 1 FUNC W,I,UsDt|
- 2 33c1 |
- 3 ADDR nnnnnnnn|
- 4 /00000009,00|
- 5 INST 33c0 |
-
- FUNC shows the specific information concerning the memory access that
- caused the bus/address error.
- The first letter gives the direction of the access, W = write, R = read.
- The second letter gives what state the 68000 was in when the error occured
- I = executing an instruction, N = not executing an instruction (responding
- to an interrupt, another trap, etc...)
- The third field represents the function code that was on pins FC0,FC1 and
- FC2 of the 68000. It can be:
- UsDt...user data ; accessing source or destination
- UsPg...user program ; reading an instruction
- SpDt...supervisor data
- SpPg...supervisor program
- IAck...interrupt acknowledge
- ????...something else TrapII doesn't know how to interpret.
- Below (line 2) is the whole hex value of the function code the 68000 dumped
- on the stack. This is only useful if TrapII's interpretation of this value
- is not enough.
-
- ADDR shows the address that caused the bus/address error. It is given
- first as an absolute address (line 3), then as an offset and hunk number
- (line 4), like the PC.
-
- INST shows the hex value of the instruction the 68000 was executing when the
- trap occurred.
-
-
-
- How TrapII works:
- (limited overview, skips many details, but lets you know what happens to
- the target)
-
- TrapII adds to the AddTask() call a bit of code that compares the new
- task's trap code (TC_TRAPCODE) with both the system default (TaskTrapCode*)
- and the TC_TRAPCODE of TrapII itself. This is because TC_TRAPCODE of a
- task started by a CLI or workbench is not the system default (I don't know
- why). If the new task is using either, then TC_TRAPCODE is changed to
- point to TrapII's trap handler.**
-
- Then TrapII waits for a signal from its trap handler.
-
- When a new task causes a trap to occur (and has not installed its own trap
- handler), TrapII's handler is executed.
- The handler dumps the 68000's registers, the 68000's stack frame in a
- buffer, signals TrapII, and invents a new stack frame that clears T and S
- bits of the SR, and changes the PC to point to TrapII's target_wait code,
- evens the USP to TrapII's ministack, and rte's.
-
- The target now executes the target_wait code, which consists of just Wait(0).
-
- TrapII is reawakened, opens a new window and all that, and goes back to
- sleep.
-
- When [Restart], [Trace] or [Next] is hit, then the target's wait stack frame
- is altered to point to TrapII's restart_target code, and the target is
- reawakened.
-
- The target now executes the restart_target code, which restores the regis-
- ters to what was displayed in the TrapII window, and control proceeds to
- where the target left off.
-
- [Next] is done by computing the length of the BSR[.S] or JSR, or getting
- the "return address" off the top of the stack, and putting a TRAP #0 at that
- next instruction. Then, whenever that task traps, if it trapped because
- of that TRAP #0, then it is cosidered a Next trap, the word altered to put
- the TRAP #0 is restored, and the PC is backed up 2 bytes so that the next
- instruction is that which was originally there. (If you have a disassembler
- you can see this: [Next] into a loop that contains a TRAP #$n. Once the
- target has hit the TRAP #$n, look at the instruction following the BSR or
- JSR you used to enter the subroutine. It will be the TRAP #0 TrapII put
- there. Once you [Restart] the target, and it exits the subroutine, TrapII's
- TRAP #0 is reached, and the code is restored to what is was before, which
- your disassembler will show you too if you look at that address again.)
- Of course, this is in fact a form of that great crasher of harvard
- architecture machines, self-modifying code, but at the top of this doc
- file I did say that TrapII did some hacks, and this is one of them
- (just keep this in mind if you are using a cache).
-
- * TrapII does NOT change TaskTrapCode(execbase), because I do not see any
- advantage in doing this; I found no task that used it.
-
- ** This way, if a task is going to use its own trap handler, either by
- later changing the value TC_TRAPCODE, or by having the task's launcher set
- it, TrapII will not get in the way.
- This also means any task started before TrapII was run will still be using
- the system's trap handler, which is why `run' was required to run the demo.
-
-
-
- Limitations, Problems & Additional Notes:
-
- Because of the way the trap handler and TrapII interact, there is a short
- time period between the time the trap occurred and the window is opened
- during which a second trap, will not be reported by TrapII. However, the
- offending task will be put into a perpetual wait state (Wait(0)).
- This time period lasts from when the trap occurs to a bit before the window
- is opened. This includes two AllocMem() calls.
-
- It is not such a good idea to have TrapII running at a very low priority;
- In order to display its windows, TrapII does have to run. Priority 0 is
- good enough in most cases, but if you have customized the priorities of
- various tasks on your system, then you may need to run TrapII at a different
- priority.
-
- TrapII will only effect tasks started (AddTask()) after it was run.
- This means that if you open a CLI, type "run trapii", then "your program",
- your program will NOT be using TrapII's trap handler, because "your program"
- is running using the CLI's task structure, and that was added to the system
- when the CLI was opened--before TrapII was run. However, if you typed "run
- your program", "your program" would use TrapII's trap handler, because run
- started a new task for "your program", and that task was started after
- TrapII was run.
-
-
-
- Use:
-
- Because targets started different ways seem to have different trap handling
- code, in order to be sure TrapII will work, TrapII must be started in the
- same manner the target will be started. For this reason, TrapII can be
- started from both a CLI or Workbench. It is true that sometimes, on some
- setups, with some programs running or not running, that a TrapII started
- one way can trap programs started another. However this behavior cannot be
- guaranteed; if it works on your system, use it if you like, but remember
- if, all of a sudden, TrapII isn't intercepting your program's errors any
- more, you will have to start TrapII the way I recommend.
-
- NOTE: the author has used this program to debug AmigaDOS device handlers
- under 1.3 and a beta 2.0 by starting it running with
- run TrapII
- from a CLI. I guess the DOS's startup-a-handler routine uses the same trap
- handler as run. However C= makes no promises that this will work forever.
-
- WB:
- just double-click on icon
-
- CLI:
- Here it seems that whether a task is started by:
- target_name
- or with a run, it doesn't change the trap handler so you can start TrapII
- with:
- run TrapII
- or, better, with:
- run <nil: >nil: TrapII
- If you are using arun (arp's run), then TrapII can be started with arun:
- arun >nil: TrapII noio
- because, it seems, arun uses the same trap handler than run (ArpRelease1.3)
-
- If TrapII must be started at a non zero priority (let's use 3), then you
- can use either:
- ChangeTaskPri 3
- TrapII
- or:
- ChangeTaskPri 3
- Run <nil: <nil: TrapII
- or:
- ARun >nil: TrapII pri 3 noio
-
- Now clever users may well be thinking doing this in their startup-sequence.
- This may work on your machine, but it does not on the author's. It seems
- the startup-sequence's trap handling code is not the same as later CLI's!
- However it might work with your setup, so don't let this dissuade you from
- trying.
-
- However, it does seem that a task started from workbench has the same trap
- handler as one started from a CLI (it seems everyone is using CreateProc()).
-
-
-
- I can be reached through:
-
- Nicolas Dade
- 405 W Delaware
- Urbana, IL, 61801 (USA)
-
- or maybe nsd20463@uxa.cso.uiuc.edu
-
-
-
-